﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using Microsoft.ApplicationBlocks.Data;
using ZEBuz.Questionnaire.Lib.Util;
using System.Data;
using System.Reflection;
using ZEBuz.Questionnaire.Lib.Core;

namespace ZEBuz.Questionnaire.Lib.Entities
{
    /// <summary>
    /// 用户与问卷表单关系
    /// </summary>
    public class QuestionnaireUser
    {
        public int Seqno { get; set; }
        //todo: 有user对象，考虑去掉这些冗余属性?
        public string UserId { get; set; }
        public int QuestionnaireId { get; set; }
        public string UserAnswerString { get; set; }
        /// <summary>
        /// 表单对象
        /// </summary>
        public Questionnaire Questionnaire { get; set; }
        /// <summary>
        /// 问卷表单全部问题的用户选项
        /// </summary>
        public List<UserAnswer> UserAnswers { get; set; }
        public List<CategoryTotalPoint> UserAnswerByCategories { get; set; }
        /// <summary>
        /// 用户对象
        /// </summary>
        public User User { get; set; }
        public DateTime InsertDT { get; set; }
        public DateTime UpdateDT { get; set; }

        public QuestionnaireUser()
        {
            UserAnswers = new List<UserAnswer>();
            UserAnswerByCategories = new List<CategoryTotalPoint>();
        }

        public QuestionnaireUser(int seqno)
            : this()
        {
            QuestionnaireUser qu = Get(seqno);
            foreach (var p in qu.GetType().GetProperties())
            {
                p.SetValue(this, p.GetValue(qu, null), null);
            }
        }

        private QuestionnaireUser Get(int seqno)
        {
            QuestionnaireUser qu = CacheHelper.GetFromCache<QuestionnaireUser>(CacheHelper.CACHE_QuestionnaireUser_Seqno + seqno);

            if (qu != null) return qu;

            qu = new QuestionnaireUser();

            using (SqlConnection conn = new SqlConnection(Const.ConnectionString))
            {
                if (conn.State != System.Data.ConnectionState.Open)
                    conn.Open();

                string sql = "SELECT Seqno,UserId,QuestionnaireId,UserAnswer,Insertdt,Updatedt FROM QuestionnaireUser uq WHERE seqno = " + seqno;
                DataSet ds = SqlHelper.ExecuteDataset(conn, CommandType.Text, sql);
                DataTable dt = (ds != null && ds.Tables.Count >= 1) ? ds.Tables[0] : null;
                if (dt != null && dt.Rows.Count >= 1)
                {
                    DataRow dr = dt.Rows[0];
                    // mapping
                    qu.Seqno = dr["seqno"].ToString().ToInt();
                    qu.UserId = dr["userid"].ToString();
                    qu.QuestionnaireId = dr["QuestionnaireId"].ToString().ToInt();
                    qu.UserAnswerString = dr["useranswer"].ToString();
                    qu.InsertDT = dr["insertdt"].ToString().ToDateTime();
                    qu.UpdateDT = dr["Updatedt"].ToString().ToDateTime();
                    qu.Questionnaire = new Questionnaire().Get(qu.QuestionnaireId);
                    qu.UserAnswers = UserAnswer.GetList(qu.UserAnswerString, qu.Questionnaire);
                    qu.User = new User().Get(qu.UserId);
                    setUserAnswerByCategories(ref qu);
                }

                CacheHelper.AddToCache<QuestionnaireUser>(CacheHelper.CACHE_QuestionnaireUser_Seqno + seqno, qu);
            }

            return qu;
        }

        public int Add()
        {
            int seqno = -1;

            using (SqlConnection conn = new SqlConnection(Const.ConnectionString))
            {
                if (conn.State != System.Data.ConnectionState.Open)
                    conn.Open();

                try
                {
                    DateTime dt = System.DateTime.Now;
                    string sql = string.Format(
                        "INSERT INTO QuestionnaireUser (UserId,QuestionnaireId,UserAnswer,InsertDT) VALUES ('{0}',{1},'{2}','{3}');SELECT CAST(scope_identity() AS int)",
                        this.UserId,
                        this.QuestionnaireId,
                        this.UserAnswerString,
                        dt.ToString());
                    object oSeqno = SqlHelper.ExecuteScalar(conn, CommandType.Text, sql);
                    seqno = oSeqno == null ? -1 : (int)oSeqno;
                }
                catch (Exception ex)
                {
                    LogHelper.Log("QN" + this.QuestionnaireId, this.UserAnswerString, ex.Message, ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                }
            }

            return seqno;
        }

        public static DataTable List(int questionnaireId, int userId)
        {
            DataTable ret = null;

            using (SqlConnection conn = new SqlConnection(Const.ConnectionString))
            {
                if (conn.State != System.Data.ConnectionState.Open)
                    conn.Open();

                try
                {
                    string sql = "SELECT Seqno,UserId,QuestionnaireId,UserAnswer,InsertDt FROM QuestionnaireUser uq";
                    DataSet ds = SqlHelper.ExecuteDataset(conn, CommandType.Text, sql);
                    ret = (ds != null && ds.Tables.Count >= 1) ? ds.Tables[0] : null;
                }
                catch (Exception ex)
                {
                    throw;
                }
            }

            return ret;
        }

        /// <summary>
        /// 分析用户问卷结果
        /// </summary>
        /// <param name="userAnswerString">qid.optid|..</param>
        /// <remarks>
        /// 拿到用户答案串后，再行分析，最后将报表对象入库
        /// </remarks>
        private void setUserAnswerByCategories(ref QuestionnaireUser qu)
        {
            if (string.IsNullOrEmpty(qu.UserAnswerString) || qu.QuestionnaireId <= 0)
            {
                throw new NotImplementedException("SetUserAnswerByCategories()方法参数错误");
            }

            if (qu.Questionnaire == null)
                qu.Questionnaire = new Questionnaire().Get(qu.QuestionnaireId);
            if (qu.UserAnswers == null)
                qu.UserAnswers = UserAnswer.GetList(qu.UserAnswerString, qu.Questionnaire);

            foreach (var cate in qu.Questionnaire.QuestionnaireDTO.categories)
            {
                List<UserAnswer> answersOfCate = qu.UserAnswers
                    .FindAll(o => o.Question != null && cate.questionIds.Split(',').Contains(o.Question.id));

                if (answersOfCate != null && answersOfCate.Count > 0)
                {
                    int score = 0;
                    foreach (var cateAns in answersOfCate)
                    {
                        score += cateAns.Point;
                    }

                    decimal avg = Math.Round((score / (decimal)cate.questionIds.Length), 2);

                    XMLQuestion.XMLQuestionCategory.XMLQuestionCategoryLevel lvl = null;

                    if (qu.Questionnaire.QuestionnaireDTO.measureType == MeasureType.Average)
                    {
                        lvl = cate.levels.Find(l => l.max >= avg && l.min <= avg);
                    }
                    if (qu.Questionnaire.QuestionnaireDTO.measureType == MeasureType.TotalScore)
                    {
                        lvl = cate.levels.Find(l => l.max >= score && l.min <= score);
                    }

                    qu.UserAnswerByCategories.Add(new CategoryTotalPoint
                    {
                        Category = cate,
                        TotalPoint = score,
                        Average = avg,
                        UserOptionLevel = lvl
                    });
                }
            }
        }
    }

    //算法步骤
    //1. 先拿出问题，再拿出分类，将所有分类中的问题拿到用户对应的分数，再计分数
    //2. 得出每个分类的总分，入属性
    //3. 分类平均值
    public class CategoryTotalPoint
    {
        public XMLQuestion.XMLQuestionCategory Category { get; set; }
        public int TotalPoint { get; set; }
        public decimal Average { get; set; }
        public XMLQuestion.XMLQuestionCategory.XMLQuestionCategoryLevel UserOptionLevel { get; set; }
    }
}